/*
 * Server.java
 *
 * Implements the remote object
 * Note: The object must extend from UnicastRemoteObject
 *       The object must implement the associated interface
 *
 */

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.List;

@SuppressWarnings("serial")
public class RMIServer extends java.rmi.server.UnicastRemoteObject implements RemoteInterface {

	//--RMI client-server stuff-----
	RemoteInterface rmiClient;
	Registry registry;
	//------------------------------

	
	public int CriticalSectionDelay;
	public int ProcessingDelay;
	
	public boolean mInitialTokenPossesion;
	
	public int mClientPort;


	//----------------------------------------------
	private DeptModuleInfo mCurrDeptModule;
	private DeptModuleInfo mLeftDeptModule;
	private DeptModuleInfo mRightDeptModule;
	private DeptModuleInfo mRight_RightDeptModule;
	
	private boolean mHasToken;
	private boolean mHasRequests;
	
	//----------------------------------------------
	

	public synchronized DeptModuleInfo getmCurrDeptModule() {
		return mCurrDeptModule;
	}

	public synchronized void setmCurrDeptModule(DeptModuleInfo dept) {
		mCurrDeptModule = dept;
	}

	public synchronized DeptModuleInfo getmLeftDeptModule() {
		return mLeftDeptModule;
	}

	public synchronized void setmLeftDeptModule(DeptModuleInfo dept) {
		mLeftDeptModule = dept;
	}

	public synchronized DeptModuleInfo getmRightDeptModule() {
		return mRightDeptModule;
	}

	public synchronized void setmRightDeptModule(DeptModuleInfo dept) {
		mRightDeptModule = dept;
	}

	public synchronized DeptModuleInfo getmRight_RightDeptModule() {
		return mRight_RightDeptModule;
	}

	public synchronized void setmRight_RightDeptModule(DeptModuleInfo dept) {
		mRight_RightDeptModule = dept;
	}


	public synchronized void setmHasToken(boolean val) {
		this.mHasToken = val;
		if (val)		//only notify() this thread to wake up if you ever set mHasToken = true
		{
			notify();
		}
	}
	
	public synchronized boolean getmHasRequests() {
		return mHasRequests;
	}

	public synchronized void setmHasRequests(boolean val) {
		mHasRequests = val;
	}
	
	/**
	 * @param int day_number
	 * @return String result
	 */
	public synchronized String lookup(int day_number) throws RemoteException
	{
		setmHasRequests(true);
		while (!mHasToken) {
            try {
                wait();
            } catch (InterruptedException e) { }
        }
		String result = "";
		try {
			
			String line = Files.readAllLines(Paths.get("Schedule.dat"), Charset.defaultCharset()).get(day_number-1);
			
			String[] array = line.split(" : ");
			
			result = array[1];
		
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.out.println("Schedule not found! Please place <schedule file> in " + System.getProperty("user.dir") + " . Thanks! Server exiting!");
			System.exit(0);
		}
		setmHasRequests(false);
		return result;
	}

	/**
	 * @param int day_number
	 * @return boolean
	 */
	public synchronized String reserve (int day_number) throws RemoteException
	{
		setmHasRequests(true);
		while (!mHasToken) {
            try {
                wait();
            } catch (InterruptedException e) { }
        }
		try {
			
			List<String> lines = Files.readAllLines(Paths.get("Schedule.dat"), Charset.defaultCharset());
			
			if (!lines.get(day_number-1).contains("FREE"))
				return "OCCUPIED!";
			
			lines.set(day_number-1, "December " + day_number + " : " + "reserved by " + "Avinash" );
			
			PrintWriter pw= new PrintWriter(new FileOutputStream("Schedule.dat")); 
			for(String line: lines) {
			  pw.println(line);
			}
			pw.close();
			System.out.println("Reservation made!");
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.out.println("Schedule not found! Please place <schedule file> in " + System.getProperty("user.dir") + " . Thanks! Server exiting!");
			System.exit(0);
		}
		setmHasRequests(false);
		return "RESERVED!";
	}
	
	public void Initialize() throws RemoteException {
		try {

			registry = LocateRegistry.createRegistry(mClientPort);
			registry.rebind(mCurrDeptModule.mName, this);
			System.out.println("Server Ready for Clients at Port Number " + mClientPort);
		
		} catch (RemoteException e) {
			throw e;
		}
	}

	public void loadFromFile(String filename) {
		try {
			List<String> lines = Files.readAllLines(Paths.get(filename), Charset.defaultCharset());
			
			CriticalSectionDelay = Integer.parseInt(lines.get(0).split(" : ")[1]) * 1000;
			ProcessingDelay = Integer.parseInt(lines.get(1).split(" : ")[1]) * 1000;
			
			mInitialTokenPossesion = Boolean.parseBoolean(lines.get(2).split(" : ")[1]);
			
			mClientPort = Integer.parseInt(lines.get(3).split(" : ")[1]);
			
			mCurrDeptModule = new DeptModuleInfo();
			mCurrDeptModule.mName = lines.get(4).split(" : ")[1];
			mCurrDeptModule.mTokenSocketPortNumber = Integer.parseInt(lines.get(5).split(" : ")[1]);
			
			mLeftDeptModule = new DeptModuleInfo();
			mLeftDeptModule.mName = lines.get(6).split(" : ")[1];
			mLeftDeptModule.mTokenSocketPortNumber = Integer.parseInt(lines.get(7).split(" : ")[1]);
			
			mRightDeptModule = new DeptModuleInfo();
			mRightDeptModule.mName = lines.get(8).split(" : ")[1];
			mRightDeptModule.mTokenSocketPortNumber = Integer.parseInt(lines.get(9).split(" : ")[1]);
			


		} catch (IOException e) {
			System.out.println("Topology file not found! Please place <topology file> in " + System.getProperty("user.dir") + " . Thanks! Server exiting!");
			System.exit(0);
		} 
	}
	
	public RMIServer(String filename) throws RemoteException {

		loadFromFile(filename);

		mRight_RightDeptModule = new DeptModuleInfo();	//don't know yet
	}

	static public void main(String args[]) {
		try {

			RMIServer server = new RMIServer(args[0]);

			server.Initialize();
			
			TokenRequestHandler tokenRequestHandler = new TokenRequestHandler(server);	//pass in 'server' because its shared between all the threads
			tokenRequestHandler.start();
			

		} catch (Exception e) {
			System.exit(1);
		}
	}
}